$$ \newcommand{\floor}[1]{\left\lfloor{#1}\right\rfloor} \newcommand{\ceil}[1]{\left\lceil{#1}\right\rceil} \renewcommand{\mod}{\,\mathrm{mod}\,} \renewcommand{\div}{\,\mathrm{div}\,} \newcommand{\metar}{\,\mathrm{m}} \newcommand{\cm}{\,\mathrm{cm}} \newcommand{\dm}{\,\mathrm{dm}} \newcommand{\litar}{\,\mathrm{l}} \newcommand{\km}{\,\mathrm{km}} \newcommand{\s}{\,\mathrm{s}} \newcommand{\h}{\,\mathrm{h}} \newcommand{\minut}{\,\mathrm{min}} \newcommand{\kmh}{\,\mathrm{\frac{km}{h}}} \newcommand{\ms}{\,\mathrm{\frac{m}{s}}} \newcommand{\mss}{\,\mathrm{\frac{m}{s^2}}} \newcommand{\mmin}{\,\mathrm{\frac{m}{min}}} \newcommand{\smin}{\,\mathrm{\frac{s}{min}}} $$

Prijavi problem


Obeleži sve kategorije koje odgovaraju problemu

Još detalja - opišite nam problem


Uspešno ste prijavili problem!
Status problema i sve dodatne informacije možete pratiti klikom na link.
Nažalost nismo trenutno u mogućnosti da obradimo vaš zahtev.
Molimo vas da pokušate kasnije.

Израчунавање координата

Слике које желимо да нацртамо често садрже неку правилност. То може бити део који се понавља, симетрија у односу на усправну или водоравну осу и слично. Да би слике изгледале као што желимо, не можемо све координате да изаберемо произвољно. Уместо тога, неке величине можемо да изаберемо, а затим остале величине треба израчунати. Узмимо на пример слику кућице из једног од претходних задатака.

../_images/drawing_house.png

Да бисмо добили овакву слику помоћу програма, потребно је извесно рачунање. Примећујемо да је слика осносиметрична (у односу на усправну осу симетрије формулара). Осим тога, прозори на кући су исте величине, а лајсне на њима спајају средине наспрамних ивица. Због ових правилности постоје одређене везе између координата значајних тачака слике. Да бисмо те везе могли да запишемо, увешћемо неке ознаке. Нека је:

  • \(W_z, H_z\) - ширина и висина зидова (жутог дела куће)

  • \(H_k\) - висина крова

  • \(a\) - дужина странице прозора

  • \(W_v, H_v\) - ширина и висина врата

  • \(m\) - растојање врха крова од горње ивице слике

  • \(D_{kp}\) - растојање крова од горње ивице било ког прозора

  • \(D_{pp}\) - растојање између два прозора

  • \(x_c\) - x координата центра слике

../_images/drawing_house_meas.png

Сада се све координате значајних тачака могу изразити помоћу ових величина. Навешћемо формуле само за неке од тачака:

  • Темена троугла који представља кров су \((x_c - {W_z \over 2}, m + H_k), (x_c, m), (x_c + {W_z \over 2}, m + H_k)\)

  • Горње лево теме зидова (жути правоугаоник) је \((x_c - {W_z \over 2}, m + H_k)\)

  • Горње лево теме левог прозора је \((x_c - {D_{pp} \over 2} - a, m + H_k + D_{kp})\)

Слично се могу изразити и координате горњег левог темена десног прозора и координате крајева лајсни на прозорима (црних усправних и водоравних дужи које полове прозре).

Све ово значи да мере које су приказане на слици можемо да изаберемо мање или више слободно, а затим потребне параметре функција за цртање можемо да израчунамо. Изаберимо, на пример, \(W_z = 180\), \(H_z = 160\), \(H_k = 100\), \(a = 50\), \(W_v = 60\), \(H_v = 80\), \(m = 20\), \(D_{kp} = 20\), \(D_{pp} = 40\). Знајући да је \(x_c = 150\), израчунавамо потребне координате. Након што израчунамо координате које се појављују као параметри функција за цртање, добиојамо следећу функцију Form1_Paint:

private void Form1_Paint(object sender, PaintEventArgs e)
{
    Graphics g = e.Graphics;
    Brush zutaCetka = new SolidBrush(Color.Yellow);
    Brush crvenaCetka = new SolidBrush(Color.Red);
    Brush neboPlavaCetka = new SolidBrush(Color.SkyBlue);
    Brush braonCetka = new SolidBrush(Color.Brown);
    Pen olovka = new Pen(Color.Black);
    Point[] krov = new Point[] { new Point(60, 120), new Point(150, 20), new Point(240, 120) };

    g.FillRectangle(zutaCetka, 60, 120, 180, 160);     // zidovi kuce
    g.FillPolygon(crvenaCetka, krov);                  // krov
    g.FillRectangle(neboPlavaCetka, 80, 140, 50, 50);  // levi prozor
    g.DrawLine(olovka, 80, 165, 130, 165);             // leva vodoravna lajsna
    g.DrawLine(olovka, 105, 140, 105, 190);            // leva uspravna lajsna
    g.FillRectangle(neboPlavaCetka, 170, 140, 50, 50); // desni prozor
    g.DrawLine(olovka, 170, 165, 220, 165);            // desna vodoravna lajsna
    g.DrawLine(olovka, 195, 140, 195, 190);            // desna uspravna lajsna
    g.FillRectangle(braonCetka, 120, 200, 60, 80);     // vrata
}

Код је уредан и све је у њему прегледно и јасно. Међутим, ако сте пробали да самостално изаберете полазне величине, или покушали да „од нуле” помоћу програма нацртате ову или неку сличну слику, вероватно сте приметили да то није сасвим једноставно. Може се догодити да су после првог покушаја прозори сувише мали, или сувише велики, или сувише размакнути, или сувише високо, или да су врата превише уска, или … У том случају треба променити неке од полазних величина и поновити рачун. Вероватно ће нам требати неколико покушаја (итерација) да дођемо до слике којом смо задовољни.

../_images/drawing_house_a1.png ../_images/drawing_house_a2.png ../_images/drawing_house_a3.png

Проблем је у томе што током тог испробавања рачунање треба стално понављати, а то онда већ постаје досадно и подложно грешкама. Зато је много боље да се потребно рачунање угради директно у програм који ће слику и приказивати. Тако долазимо до следеће функције Form1_Paint.

private void Form1_Paint(object sender, PaintEventArgs e)
{
    Graphics g = e.Graphics;
    Brush zutaCetka = new SolidBrush(Color.Yellow);
    Brush crvenaCetka = new SolidBrush(Color.Red);
    Brush neboPlavaCetka = new SolidBrush(Color.SkyBlue);
    Brush braonCetka = new SolidBrush(Color.Brown);
    Pen olovka = new Pen(Color.Black);
    int xc = ClientSize.Width / 2;

    int marginaGore = 20;
    int visinaKrova = 100;
    int sirinaKuce = 180;
    int visinaKuce = 160;
    int stranicaProzora = 50;
    int krov_prozor = 20;
    int prozor_prozor = 40;
    int sirinaVrata = 60;
    int visinaVrata = 80;

    Point kucaGL = new Point(xc - sirinaKuce / 2, marginaGore + visinaKrova);
    Point[] krov = new Point[] { kucaGL, new Point(xc, marginaGore), new Point(kucaGL.X + sirinaKuce, kucaGL.Y) };
    Point LeviProzorGL = new Point(xc - prozor_prozor / 2 - stranicaProzora, kucaGL.Y + krov_prozor);
    Point DesniProzorGL = new Point(LeviProzorGL.X + stranicaProzora + prozor_prozor, LeviProzorGL.Y);
    Point VrataGL = new Point(xc - sirinaVrata / 2, kucaGL.Y + visinaKuce - visinaVrata);

    // zidovi kuce
    g.FillRectangle(zutaCetka, kucaGL.X, kucaGL.Y, sirinaKuce, visinaKuce);

    // krov
    g.FillPolygon(crvenaCetka, krov);

    // levi prozor
    g.FillRectangle(neboPlavaCetka, LeviProzorGL.X, LeviProzorGL.Y, stranicaProzora, stranicaProzora);

    // leva vodoravna lajsna
    g.DrawLine(olovka,
        LeviProzorGL.X, LeviProzorGL.Y + stranicaProzora / 2,
        LeviProzorGL.X + stranicaProzora, LeviProzorGL.Y + stranicaProzora / 2);

    // leva uspravna lajsna
    g.DrawLine(olovka,
        LeviProzorGL.X + stranicaProzora / 2, LeviProzorGL.Y,
        LeviProzorGL.X + stranicaProzora / 2, LeviProzorGL.Y + stranicaProzora);

    // desni prozor
    g.FillRectangle(neboPlavaCetka, DesniProzorGL.X, DesniProzorGL.Y, stranicaProzora, stranicaProzora);

    // desna vodoravna lajsna
    g.DrawLine(olovka,
        DesniProzorGL.X, DesniProzorGL.Y + stranicaProzora / 2,
        DesniProzorGL.X + stranicaProzora, DesniProzorGL.Y + stranicaProzora / 2);

    // leva uspravna lajsna
    g.DrawLine(olovka,
        DesniProzorGL.X + stranicaProzora / 2, DesniProzorGL.Y,
        DesniProzorGL.X + stranicaProzora / 2, DesniProzorGL.Y + stranicaProzora);

    // vrata
    g.FillRectangle(braonCetka, VrataGL.X, VrataGL.Y, sirinaVrata, visinaVrata);
}

Иако је ова функција знатно дужа од претходне, она има очигледну предност - сада је много лакше експериментисати. Па и када добијемо слику којом смо задовољни, можда ћемо касније пожелети да направимо још неке слике, или да дамо програм некоме ко ће хтети да промени изглед кућице у својој копији програма. Ова верзија функције је много погоднија за поновну употребу и добијање нових сличних слика кућице.

Задаци за вежбу

Изаберите неке (или све) од понуђених слика и покушајте да нацртате што приближније слике помоћу програма. Користите израчунавање координата онако како је овде објашњено.

../_images/drawing_calc_no_parking.png ../_images/drawing_calc_alternating_parking.png ../_images/drawing_calc_camping_ground.png ../_images/drawing_calc_pass_advantage.png ../_images/drawing_calc_traffic_lane_closure.png ../_images/drawing_calc_highway_end.png